package cn.wen.eeayjoke.presenter;

import android.os.Handler;
import android.os.Looper;

import com.google.gson.Gson;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.List;
import java.util.Map;

import cn.wen.core.http.callback.OkHttpCallback;
import cn.wen.eeayjoke.entity.bean.base.RequestHead;
import cn.wen.eeayjoke.entity.bean.base.ResponseBean;
import cn.wen.eeayjoke.entity.bean.base.ResponseHead;

/**
 * Created by Administrator on 2018/3/17.
 */

public abstract class HttpCallback<T> extends OkHttpCallback<T> {
    private static Gson gson = new Gson();
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private ResponseHead mHead;

    @Override
    public void onBefore(Map<String, Object> params) {
        RequestHead head = new RequestHead();
        params.put("head", head);
    }

    @Override
    public void onError(final Throwable e) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                onError(mHead, e);
            }
        });

    }

    @Override
    public void onSucceed(String result) {
        try {
            Type genType = this.getClass().getGenericSuperclass();
            Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
            // 这是泛型类型
            Type actualType = params[0];
            // 普通的类
            if (!(actualType instanceof Class)) {
                Type typeOfT = ((ParameterizedType) actualType).getActualTypeArguments()[0];
                Type listType = new ParameterizedTypeImpl(List.class, new Type[]{typeOfT});
                // 根据List<T>生成完整的Result<List<T>>
                actualType = new ParameterizedTypeImpl(ResponseBean.class, new Type[]{listType});
            } else {
                // 这是ResponseBean<T>真正的类型
                actualType = new ParameterizedTypeImpl(ResponseBean.class, new Type[]{actualType});
            }

            ResponseBean<T> bean = gson.fromJson(result, actualType);
            final T data = bean.data;
            mHead = bean.head;
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (mHead != null) {
                        if (mHead.bcode.equals("1")) {
                            onSucceed(mHead, data);
                        } else {
                            onError(mHead, new RuntimeException(mHead.bmessage + ""));
                        }
                    }
                }
            });
        } catch (Exception e) {
            onError(e);
        }

    }

    private static Class<?> getRawType(Type type) {
        if (type instanceof Class<?>) {
            return (Class<?>) type;
        }
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type rawType = parameterizedType.getRawType();
            if (!(rawType instanceof Class)) throw new IllegalArgumentException();
            return (Class<?>) rawType;
        }
        if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            return Array.newInstance(getRawType(componentType), 0).getClass();
        }
        if (type instanceof TypeVariable) {
            // We could use the variable's bounds, but that won't work if there are multiple. Having a raw
            // type that's more general than necessary is okay.
            return Object.class;
        }
        if (type instanceof WildcardType) {
            return getRawType(((WildcardType) type).getUpperBounds()[0]);
        }
        throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
                + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
    }

    public void onError(ResponseHead head, Throwable e) {
        e.printStackTrace();
    }

    public abstract void onSucceed(ResponseHead head, T data);
}
